// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef BASE_ANDROID_JNI_GENERATOR_SAMPLE_FOR_TESTS_H_
#define BASE_ANDROID_JNI_GENERATOR_SAMPLE_FOR_TESTS_H_

#include <jni.h>
#include <map>
#include <string>

#include "base/android/jni_android.h"

namespace base {
namespace android {

    // This file is used to:
    // - document the best practices and guidelines on JNI usage.
    // - ensure sample_for_tests_jni.h compiles and the functions declared in it
    // as expected.
    //
    // Methods are called directly from Java (except RegisterJNI). More
    // documentation in SampleForTests.java
    //
    // For C++ to access Java methods:
    // - GN Build must be configured to generate bindings:
    //  # Add import at top of file:
    //  if (is_android) {
    //    import("//build/config/android/rules.gni")  # For generate_jni().
    //  }
    //  # ...
    //  # An example target that will rely on JNI:
    //  component("foo") {
    //    # ... normal sources, defines, deps.
    //    #     For each jni generated .java -> .h header file in jni_headers
    //    #     target there will be a single .cc file here that includes it.
    //    #
    //    # Add a dep for JNI:
    //    if (is_android) {
    //      deps += [ ":foo_jni" ]
    //    }
    //  }
    //  # ...
    //  # Create target for JNI:
    //  if (is_android) {
    //    generate_jni("jni_headers") {
    //      sources = [
    //        "java/src/org/chromium/example/jni_generator/SampleForTests.java",
    //      ]
    //      jni_package = "foo"
    //    }
    //    android_library("java") {
    //      java_files = [
    //        "java/src/org/chromium/example/jni_generator/SampleForTests.java",
    //        "java/src/org/chromium/example/jni_generator/NonJniFile.java",
    //      ]
    //    }
    //  }
    //
    // For C++ methods to be exposed to Java:
    // - The generated RegisterNativesImpl method must be called, this is typically
    //   done by having a static RegisterJNI method in the C++ class.
    // - The RegisterJNI method is added to a module's collection of register
    //   methods, such as: example_jni_registrar.h/cc files which call
    //   base::android::RegisterNativeMethods.
    //   An example_jni_registstrar.cc:
    //
    //     namespace {
    //     const base::android::RegistrationMethod kRegisteredMethods[] = {
    //         // Initial string is for debugging only.
    //         { "ExampleName", base::ExampleNameAndroid::RegisterJNI },
    //         { "ExampleName2", base::ExampleName2Android::RegisterJNI },
    //     };
    //     }  // namespace
    //
    //     bool RegisterModuleNameJni(JNIEnv* env) {
    //       return RegisterNativeMethods(env, kRegisteredMethods,
    //                                    arraysize(kRegisteredMethods));
    //     }
    //
    //  - Each module's RegisterModuleNameJni must be called by a larger module,
    //    or application during startup.
    //
    class CPPClass {
    public:
        CPPClass();
        ~CPPClass();

        // Register C++ methods exposed to Java using JNI.
        static bool RegisterJNI(JNIEnv* env);

        // Java @CalledByNative methods implicitly available to C++ via the _jni.h
        // file included in the .cc file.

        class InnerClass {
        public:
            jdouble MethodOtherP0(JNIEnv* env,
                const base::android::JavaParamRef<jobject>& caller);
        };

        void Destroy(JNIEnv* env, const base::android::JavaParamRef<jobject>& caller);

        jint Method(JNIEnv* env, const base::android::JavaParamRef<jobject>& caller);

        void AddStructB(JNIEnv* env,
            const base::android::JavaParamRef<jobject>& caller,
            const base::android::JavaParamRef<jobject>& structb);

        void IterateAndDoSomethingWithStructB(
            JNIEnv* env,
            const base::android::JavaParamRef<jobject>& caller);

        base::android::ScopedJavaLocalRef<jstring> ReturnAString(
            JNIEnv* env,
            const base::android::JavaParamRef<jobject>& caller);

    private:
        std::map<long, std::string> map_;

        DISALLOW_COPY_AND_ASSIGN(CPPClass);
    };

} // namespace android
} // namespace base

#endif // BASE_ANDROID_JNI_GENERATOR_SAMPLE_FOR_TESTS_H_
